/**
 * @file InOut.c
 * @brief GDR input and output routines
 * @author Matt Stallmann @date 21 Dec 2001
 * $Id: InOut.c 10 2007-06-28 20:08:57Z mfms $
 */

/*
 *  Copyright (C) 1989, 2001  Matthias Stallmann, Prashant Hebbar.
 *  Contact: matt_stallmann@ncsu.edu
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License along
 *  with this program (file COPYING.txt); if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
 *  USA.
 */

#include "All.h"
#include <ctype.h>

void dump_graph(void)
{
  L_NODE * l_pt;
  vertex i;
  int flag;                     /* true if an edge has been printed for
                                   this vertex */
  printf("BEGIN GRAPH\n");
  for ( i = 0; i < number_of_vertices; i++ ) {
    if ( DEL(i) )
      continue;
    
    flag = FALSE;
    l_pt = V_FIRST(i);
    printf("%d[%s]: (", VID(i), VLABEL(i));
    while ( l_pt != NULL_EDGE ) {
      if ( IS_VALID_EJ( l_pt ) && VX_1( l_pt ) == i ) {
        if (flag) printf(", ");
        flag = TRUE;
        printf("%d[%s]", VX_2(l_pt), LABEL(l_pt));
      }
      else if (!direct) {
        if (flag) printf(", ");
        flag = TRUE;
        printf("%d[%s]", VX_1(l_pt), LABEL(l_pt));
      }
      l_pt = LNK(l_pt);
    } /* while not null */
    printf(")\n");
  } /* for i */
  printf("END GRAPH\n");
} /* print_gr_data() ends */

int read_in_gr( FILE * fd )
{
  vertex    i, id, old_number_of_vertices = 0;
  int       lx, ly, kn[2][2];
  EJ_NODE   * ej_pt;
  char      done = FALSE;
  char      code[sizeof(GDR_CODE)], label[LINE_LENGTH];
  char      error_msg_buffer[MESSAGE_LENGTH];
  int       edge_display;       /* display info for current edge */
  
  old_number_of_vertices = number_of_vertices; /* save the old max so that
                                                  graph can be cleaned up
                                                  properly */ 
  if ( fscanf(fd, "%s%d%d\n", code, &number_of_vertices, &direct) != 3 ) {
    sprintf( error_msg_buffer,
             "File I/O error\nat beginning:\n%s %d %d\n",
             code, number_of_vertices, direct );
    popup_message( 0, 0, error_msg_buffer );
    return(1);
  }
  if (strcmp(code, GDR_CODE)){
    sprintf( error_msg_buffer,
             "File does not begin\nwith GDR code.\nFile begin = %s\n", code );
    popup_message( 0, 0, error_msg_buffer );
    return(1);
  }

  /* clear the existing graph, if any */
  clear_graph(0, old_number_of_vertices);
  
  /* change the directed button */
  update_directed_in_panel();

  /* start reading graph details from file */
  for (i = 0; (!done && (i < number_of_vertices)); i++) {
    if (fscanf(fd, "%d", &id) == EOF) {
      done = TRUE;
      continue;
    }
    if ( id < 0 || id >= number_of_vertices ) {
      sprintf( error_msg_buffer,
               "Vertex number %d\nis out of range\n", id );
      popup_message( 0, 0, error_msg_buffer );
      return(1);
    }
    while (i < id) {
      vx_array[i].i_am_deleted = TRUE;
      i++;
    }
#ifdef DEBUG
    fprintf( stderr, "Reading vertex %d:\n", i );
#endif
    vx_array[i].my_id = i;
    vx_array[i].i_am_deleted = FALSE;
    if( vx_array[i].my_adj_list == NULL )
      vx_array[i].my_adj_list = new_list();

    /* read vertex position, label, label position, and display info */
    if ( fscanf( fd, "%d%d", &(XCORD(i)), &(YCORD(i))) != 2 ) {
      sprintf( error_msg_buffer,
               "Error while reading\nposition of vertex %d:\n(%d,%d)\n",
               i, XCORD(i), YCORD(i) );
      popup_message( 0, 0, error_msg_buffer );
      return(1);
    }
#ifdef DEBUG
    fprintf( stderr, "  position = (%d,%d)\n", XCORD(i), YCORD(i) );
#endif
    if ( XCORD(i) < 0 || XCORD(i) > window_width()
         || YCORD(i) < 0 || YCORD(i) > window_height() ) {
      sprintf( error_msg_buffer,
               "Warning: positon of vertex %d\nout of range:\n(%d,%d)\n",
               i, XCORD(i), YCORD(i) );
      popup_message( 0, 0, error_msg_buffer );
    }
    if ( fscanf( fd, "%s", VLABEL(i) ) == EOF ) {
      sprintf( error_msg_buffer,
               "Error while reading\nlabel of vertex %d\n", i );
      popup_message( 0, 0, error_msg_buffer );
      return(1);
    }
#ifdef DEBUG
    fprintf( stderr, "  label = %s", VLABEL(i) );
#endif
    /* A label "_" denotes an empty string */
    if ( ! strcmp( VLABEL(i), "_" ) ) VLABEL(i)[0] = '\0';
    if ( fscanf( fd, "%d%d", &(VLX(i)), &(VLY(i))) != 2 ) {
      sprintf( error_msg_buffer,
       "Error while reading\nlabel position of vertex %d:\n(%d,%d)\n",
               i, VLX(i), VLY(i) );
      popup_message( 0, 0, error_msg_buffer );
      return(1);
    } 
#ifdef DEBUG
    fprintf( stderr, "  label position = (%d,%d)\n", VLX(i), VLY(i) );
#endif
    if ( VLX(i) < 0 || VLX(i) > window_width()
         || VLY(i) < 0 || VLY(i) > window_height() ) {
      sprintf( error_msg_buffer,
             "Warning: label positon\nof vertex %d\nout of range:\n(%d,%d)\n",
               i, VLX(i), VLY(i) );
      popup_message( 0, 0, error_msg_buffer );
    }
    if ( fscanf(fd, "%d", &(V_DB(i))) == EOF ) {
      sprintf( error_msg_buffer,
               "Error while reading\ndisplay info for vertex %d\n", i );
      popup_message( 0, 0, error_msg_buffer );
      return(1);
    }
#ifdef DEBUG
    fprintf( stderr, "  display byte = %d\n", V_DB(i) );
#endif

    /* set up the vertex label window */
    create_vlab_win(main_canvas, i);

    /* read the edges */
    while ( TRUE ) {
      /* read "other vertex" */
      if ( fscanf(fd, "%d", &id) == EOF ) {
        sprintf( error_msg_buffer,
                 "Error: expecting other vertex\nor -1 for vertex %d\n",
                 i );
        popup_message( 0, 0, error_msg_buffer );
        return(1);
      }
#ifdef DEBUG
      fprintf( stderr, "  ---> %d ()\n", id );
#endif
      if ( id == -1 ) break;    /* -1 is sentinel value for adacency list */

      if ( id < 0 || id >= number_of_vertices ) {
        sprintf( error_msg_buffer,
                 "Other vertex number %d\nis out of range for vertex %d\n",
                 id, i );
        popup_message( 0, 0, error_msg_buffer );
        return(1);
      }
      /* read edge label, 2 knots, label position, and display info */
      if ( fscanf( fd, "%s", label ) == EOF ) {
        sprintf( error_msg_buffer,
                 "Error while reading\nlabel of edge (%d,%d)\n", i, id );
        popup_message( 0, 0, error_msg_buffer );
        return(1);
      }
#ifdef DEBUG
      fprintf( stderr, "     edge label = %s\n", label );
#endif
      /* A label "_" denotes an empty string */
      if ( ! strcmp( label, "_" ) ) {
        label[0] = ' ';
        label[1] = '\0';
      }
      if ( fscanf( fd, "%d%d%d%d", &kn[0][0], &kn[0][1], &kn[1][0],
                   &kn[1][1] ) != 4 ) {
        sprintf( error_msg_buffer,
             "Error while reading\nknots for edge (%d,%d):\n[%d,%d][%d,%d]\n",
                 i, id, kn[0][0], kn[0][1], kn[1][0], kn[1][1] );
        popup_message( 0, 0, error_msg_buffer );
        return(1);
      }
#ifdef DEBUG
      fprintf( stderr, "     knots = (%d,%d) and (%d,%d)\n",  kn[0][0],
               kn[0][1], kn[1][0], kn[1][1] );
#endif
      if ( kn[0][0] < 0 || kn[0][0] > window_width()
           || kn[0][1] < 0 || kn[0][1] > window_height()
           || kn[1][0] < 0 || kn[1][0] > window_width()
           || kn[1][1] < 0 || kn[1][1] > window_height() ) {
        sprintf( error_msg_buffer,
           "Warning: knots for edge (%d,%d)\nout of range:\n[%d,%d][%d,%d]\n",
                 i, id, kn[0][0], kn[0][1], kn[1][0], kn[1][1] );
        popup_message( 0, 0, error_msg_buffer );
      }
      if ( fscanf( fd, "%d%d", &lx, &ly ) != 2 ) {
        sprintf( error_msg_buffer,
           "Error while reading\nlabel position of\nedge (%d,%d): [%d,%d]\n",
                 i, id, lx, ly );
        popup_message( 0, 0, error_msg_buffer );
        return(1);
      } 
#ifdef DEBUG
      fprintf( stderr, "     edge label position = (%d,%d)\n", lx, ly );
#endif
      if ( lx < 0 || lx > window_width()
           || ly < 0 || ly > window_height() ) {
        sprintf( error_msg_buffer,
        "Warning: label positon\nof edge (%d,%d)\nout of range:\n[%d,%d]\n",
               i, id, lx, ly );
        popup_message( 0, 0, error_msg_buffer );
      }
      if ( fscanf(fd, "%d", &edge_display) == EOF ) {
        sprintf( error_msg_buffer,
                 "Error while reading\ndisplay info for\nedge (%d,%d)\n",
                 i, id );
        popup_message( 0, 0, error_msg_buffer );
        return(1);
      }
#ifdef DEBUG
      fprintf( stderr, "     edge display byte = %d\n", edge_display );
#endif
      ej_pt = create_edge_record( i, id, label, lx, ly, kn,
                                  edge_display | DSP_MSK );
      /* insert edge into adjacency lists and list of all edges */
      add_to_list( ej_pt, ADJ( i ) );
      if( i != id ) {
        if( vx_array[id].my_adj_list == NULL )
          vx_array[id].my_adj_list = new_list();
        add_to_list( ej_pt, ADJ( id ) );
      }
      add_to_list( ej_pt, all_edges );
    } /* while TRUE */
  } /* for i */
  return(0);
} /* read_in_gr ends */

/* [modification, Philip LaFleur, 2005/09/25: added isEmptyString() and
   modified print_graph_data() to fix a bug that caused an empty label to be
   misidentified (i.e., a label consisting only of blanks should count as
   empty, but was not before the bug fix. */
char
isEmptyString (char *string)
{
  while (*string != 0)
    if (! isspace (*string++))
      return 0;
  return 1;
}

void print_graph_data( FILE * fd )
{
  edge l_pt;
  vertex i;
  char * output_label;          /* label used for output purposes */

  /* assume fd is valid and start printing */
  fprintf(fd, "%s %d %d\n", GDR_CODE, number_of_vertices, direct);

  for (i = 0; i < number_of_vertices; i++) {
    if (DEL(i))
      continue;
    
    /* replace empty label with _ if needed */
    output_label = isEmptyString(VLABEL(i)) ? "_" : VLABEL(i);
    fprintf(fd, "%d %d %d %s %d %d %d\n", i, XCORD(i), YCORD(i),
            output_label, VLX(i), VLY(i), V_DB(i));

    l_pt = V_FIRST(i);
    while ( l_pt != NULL_EDGE ) {
      if ( VX_1(l_pt) == i ) {
        /* replace empty label with _ if needed */
        output_label = isEmptyString (LABEL(l_pt)) ? "_" : LABEL(l_pt);
        fprintf(fd, " %d %s", VX_2(l_pt), output_label);
        fprintf(fd, " %d %d %d %d", KN(l_pt,0,0), KN(l_pt,0,1),
                KN(l_pt,1,0), KN(l_pt,1,1));
        fprintf(fd, " %d %d %d", LX(l_pt), LY(l_pt), E_DB(l_pt));
      }
      l_pt = LNK( l_pt );
    }
    fprintf(fd, " %d\n", -1); /* signal the end */  
  } /* for i */

  if (fd!=stdout)
    fclose(fd);
} /* print_graph_data ends */

/** end of InOut.c **/

/*  [Last modified: 2007 06 28 at 19:21:01 GMT] */
